Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

585
Visualizações
Convertir doble[,] a IntPtr C#

Necesito convertir una matriz doble en c# en un IntPtr para enviarlo correctamente a mi c DLL. He podido convertir con éxito de IntPtr a double[,] usando el método de esta respuesta . También encontré otra respuesta que está cerca de lo que necesito pero trata con matrices 1D.

Me falta algo en mi lógica y obtengo el código de error después de un bloqueo: Managed ' ha salido con el código -1073740940 (0xc0000374).

Esto es lo que tengo hasta ahora

 IntPtr p = Marshal.AllocHGlobal(rows * columns); for (int i = 0; i < rows; i++) //rows { double[] temp = new double[columns]; for (int x = 0; x < columns; x++) temp[x] = input.cells[i, x]; Marshal.Copy(temp, 0, p, columns); p = (IntPtr)(p.ToInt64() + IntPtr.Size); } toReturn.cells = p; Marshal.FreeHGlobal(p); return toReturn;

toReturn.cells es mi IntPtr dentro de una estructura que devuelvo. las celdas están estructuradas como celdas [filas, columnas]

Los IntPtr todavía son muy nuevos para mí.

Editar: gracias a Harold. sus sugerencias funcionaron maravillosamente

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Hay varias cosas mal con eso.

Primero, rows * columns no es el tamaño de los datos, es solo el número total de elementos. Los elementos no son de un byte cada uno, sino de ocho, o sizeof(double) si lo prefiere.

En segundo lugar, p se actualiza mediante p = (IntPtr)(p.ToInt64() + IntPtr.Size); (es decir, avanzándolo en 4 u 8 bytes dependiendo de qué tan grandes sean los punteros en el modo actual), pero ha escrito columns * 8 (o columns * sizeof(double) ) bytes de datos. Avanzar p en menos de columns * 8 hace que las escrituras se sobrescriban entre sí, por lo que no todos los datos terminan en el resultado. Por cierto, las conversiones complicadas aquí en realidad no son necesarias, puede agregarlas directamente a un IntPtr , desde .NET 4.

En tercer lugar, se cambia p en el ciclo, lo que no es malo por sí solo, pero se hace de una manera que pierde el rastro del puntero original. toReturn.cells = p; y Marshal.FreeHGlobal(p); use una p que no se refiera al área que asignó, usan una p que ahora apunta justo más allá del final de los datos (bueno, apuntaría allí si p se actualizara en la cantidad correcta). Debe recordarse la p original.

En cuarto lugar, liberar los datos antes de devolverlos significa que ahora ya no existen, por lo que cualquier código al que se pasen estos datos todavía no los tiene: tiene un puntero a nada que no será válido para usar (puede funcionar accidentalmente, pero es peligroso e incorrecto).

Los tres primeros puntos son fáciles de arreglar, pero el último necesita un cambio no local en el funcionamiento de su aplicación: la memoria no se puede liberar aquí, pero debería liberarse en algún momento, es decir, cuando el usuario de los datos haya terminado. con eso.

Algunas correcciones aplicadas:

 int stride = columns * sizeof(double); IntPtr p = Marshal.AllocHGlobal(rows * stride); for (int i = 0; i < rows; i++) //rows { double[] temp = new double[columns]; for (int x = 0; x < columns; x++) temp[x] = input.cells[i, x]; Marshal.Copy(temp, 0, p + stride * i, columns); } toReturn.cells = p; return toReturn;

Tenga en cuenta que aún debe liberar la memoria en el momento adecuado.

over 4 years ago · Santiago Trujillo Relatório

0

¿Qué pasa con el uso de GHandles para llevar el IntPtr a una matriz? Primero hice una copia para evitar que el cliente sobrescribiera los datos. Desafortunadamente, debe mantener un GHandle para llamar a .Free() para evitar pérdidas de memoria. Esto impulsa la decisión de mantener no solo un IntPtr en las salidas, sino también el GHandle y la longitud de bytes FYI.

 static class Program { static void Main(string[] args) { Inputs inputs = new Inputs(); inputs.Cells = new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; var outputs = Prepare(inputs); Console.WriteLine(outputs.CellPtr); Console.WriteLine("Finish."); } static Outputs Prepare(Inputs inputs) { Outputs outputs = new Outputs(); outputs.ByteSize = Buffer.ByteLength(inputs.Cells); var temp = new double[inputs.Cells.GetLength(0), inputs.Cells.GetLength(1)]; Buffer.BlockCopy(inputs.Cells, 0, temp, 0, outputs.ByteSize); outputs.Handle = GCHandle.Alloc(inputs.Cells, GCHandleType.Pinned); outputs.CellPtr = outputs.Handle.AddrOfPinnedObject(); return outputs; } } public class Inputs { public double[,] Cells { get; set; } } public class Outputs : IDisposable { public IntPtr CellPtr { get; set; } public int ByteSize { get; set; } public GCHandle Handle { get; set; } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // dispose managed resources here } Handle.Free(); CellPtr = IntPtr.Zero; ByteSize = 0; disposedValue = true; } } ~Outputs() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(false); } // This code added to correctly implement the disposable pattern. public void Dispose() { Dispose(true); } #endregion }
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda